package cheme.ProcessModel;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

import org.eclipse.ui.views.properties.IPropertyDescriptor;

import cheme.ProcessModel.Interpreter.Interpreter;

/*
 * Can be both a publisher and subscriber of property cahnge events.
 */
public abstract class PropertyAwareObject implements IPropertyAware
{
	boolean supressUpdateProcessing = false;
	
	protected PropertyChangeSupport listeners = new PropertyChangeSupport(this);
	
//	protected transient List<PropertyChangeListener> listeners = new ArrayList<PropertyChangeListener>();

	/*--------------------------------------------------------------------------
	 * IPropertySource
	 */

	public boolean getSupressUpdateProcessing()
	{
		return supressUpdateProcessing;
	}

	public void setSupressUpdateProcessing(boolean supressUpdateEvents)
	{
		this.supressUpdateProcessing = supressUpdateEvents;
	}

	public void addPropertyChangeListener(PropertyChangeListener listener)
	{
		listeners.addPropertyChangeListener(listener);
//		listeners.add(listener);
	}

	public void removePropertyChangeListener(PropertyChangeListener listener)
	{
		listeners.removePropertyChangeListener(listener);
//		listeners.remove(listener);
	}
	
	public void removeAllPropertyChangeListener()
	{
		listeners = new PropertyChangeSupport(this);
//		listeners = new ArrayList<PropertyChangeListener>();
	}
	
	public boolean hasListener(PropertyChangeListener listener)
	{
		for(int i = 0; i < listeners.getPropertyChangeListeners().length; i++)
		{
			if(listener == ((PropertyChangeListener)listeners.getPropertyChangeListeners()[i]))
			{
				return true;
			}
		}
		
//		for(PropertyChangeListener candidate : listeners)
//		{
//			if(listener == candidate)
//			{
//				return true;
//			}
//		}
		
		return false;
	}
	
	public void firePropertyChange(PropertyChangeEvent evt)
	{
		firePropertyChange(new ChemePropertyChangeEvent(evt));
	}
	
	public void firePropertyChange(ChemePropertyChangeEvent evt)
	{
		try
		{
//			printListeners(evt.getPropertyName());
			
			PropertyChangeListener listener = null;
			PropertyChangeListener [] listenerArray = listeners.getPropertyChangeListeners(); 
			
			for(int i = 0; i < listenerArray.length; i++)
//			for(int i = 0; i < listeners.size(); i++)
			{
//				listener = listeners.get(i);
				listener = listenerArray[i];
					
				if(!(getSupressUpdateProcessing() && listener instanceof Interpreter))
				{
					listener.propertyChange(evt);
				}
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
			//System.out.print("\n\n");
		}
	}
	
	public void firePropertyChange(String propName, Object oldValue, Object newValue)
	{
		firePropertyChange(
				new ChemePropertyChangeEvent(this, propName, oldValue, newValue));
	}
	
	protected void printListeners(String propName)
	{
		int listenersCount = listeners.getPropertyChangeListeners().length;
//		int listenersCount = listeners.size();
		
		if(0 != listenersCount)
		{
			//System.out.println(getClass().getSimpleName() + " has " + Integer.toString(listenersCount) + " " + propName + " listener(s).");
			
			for(PropertyChangeListener listener : listeners.getPropertyChangeListeners())
//			for(PropertyChangeListener listener : listeners)
			{
				//System.out.println( "\t + " + listener.getClass().getSimpleName() + " is listening to " + getClass().getSimpleName() + ".");
			}
		}
	}

	/*--------------------------------------------------------------------------
	 * Stuff for property page interaction, some sublclasses might benefit from 
	 * adding this.
	 */
	public Object getEditableValue()
	{
		return this;
	}

	public IPropertyDescriptor[] getPropertyDescriptors()
	{
		return new IPropertyDescriptor[0];
	}

	public Object getPropertyValue(Object id)
	{
		return null;
	}

	public boolean isPropertySet(Object id)
	{
		return false;
	}

	public void resetPropertyValue(Object id)
	{
	}

	public void setPropertyValue(Object id, Object value)
	{
	}
	
	/*--------------------------------------------------------------------------
	 * PropertyChangeListener
	 */
	/**
	 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
	 */
	public void propertyChange(PropertyChangeEvent evt)
	{
		try
		{
			String property = evt.getPropertyName();

			if (IPropertyAware.P_INTERPRETABLE.equals(property))
			{
				handleInterpretation(evt);
			}
			else if (IPropertyAware.P_TEXT.equals(property))
			{
				handleTextChange(evt);
			}
			else if (IPropertyAware.P_CHILD.equals(property))
			{
				handleChildChange(evt);
			}
			 else if (IPropertyAware.P_INTERPRETABLE.equals(property))
			{
				handleInterpretation(evt);
			}
			else if (IPropertyAware.P_INITIAL.equals(property))
			{
				handleInitialization(evt);
			}
			else if (IPropertyAware.P_DISPOSE.equals(property))
			{
				handleDispose(evt);
			}
			else if (IPropertyAware.P_ANNOTATION.equals(property))
			{
				handleAnnotationChange(evt);
			}
			else if (IPropertyAware.P_ANNOTATIONS.equals(property))
			{
				handleAnnotationsChange(evt);
			}
			else if (IPropertyAware.P_CHILDREN.equals(property))
			{
				handleChildrenChange(evt);
			}
			else if (IPropertyAware.P_SOURCE_STREAM.equals(property))
			{
				handleSourceChange(evt);
			}
			else if (IPropertyAware.P_SINK_STREAM.equals(property))
			{
				handleTargetChange(evt);
			}
			else if (IPropertyAware.P_CONSTRAINT.equals(property))
			{
				handleBoundsChange(evt);
			}
			if (IPropertyAware.P_REORDER.equals(property))
			{
				handleReorderChange(evt);
			}
			else if (IPropertyAware.P_LAYOUT.equals(property))
			{
				handleLayoutChange(evt);
			}
			else if(IPropertyAware.P_COMPLETENESS.equals(property))
			{
				handleCompletenessChange(evt);
			}
			else if(IPropertyAware.P_CLEAR.equals(property))
			{
				handleClearChange(evt);
			}
			else if(IPropertyAware.P_BACKGROUNDCOLOR.equals(property))
			{
				handleBackgroundColorChange(evt);
			}
			else if (IPropertyAware.P_VISIBILITY.equals(property))
			{
				handleVisibilityChange(evt);
			}
			else if (IPropertyAware.P_LOCATION.equals(property))
			{
				handleLocationChange(evt);
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	

	private void handleLocationChange(PropertyChangeEvent evt) {
		// TODO Auto-generated method stub
		
	}

	private void handleVisibilityChange(PropertyChangeEvent evt)
	{	
		
	}

	protected void handleBackgroundColorChange(PropertyChangeEvent evt)
	{
	}

	/**
	 * Called console view labels are to be cleared
	 */	
	protected void handleClearChange(PropertyChangeEvent evt)
	{
	}

	protected void handleInterpretation(PropertyChangeEvent evt)
	{
	}
	
	protected void handleInitialization(PropertyChangeEvent evt)
	{
	}
	
	protected void handleDispose(PropertyChangeEvent evt)
	{
	}
	
	/**
	 * Called when change to one of the inputs occurs
	 */
	protected void handleTargetChange(PropertyChangeEvent evt)
	{
	}

	/**
	 * Called when change to one of the outputs occurs
	 */
	protected void handleSourceChange(PropertyChangeEvent evt)
	{
	}
	
	/**
	 * called when an annotation added or removed
	 */
	protected void handleAnnotationChange(PropertyChangeEvent evt)
	{
	}
	
	/**
	 * called when two or more annotations added or removed
	 */
	protected void handleAnnotationsChange(PropertyChangeEvent evt)
	{
	}
	
	/**
	 * called when a child added or removed
	 */
	protected void handleChildChange(PropertyChangeEvent evt)
	{
	}
	
	/**
	 * called when two or more children added or removed
	 */
	protected void handleChildrenChange(PropertyChangeEvent evt)
	{
	}

	/**
	 * Called when columns are re-ordered within
	 */
	protected void handleReorderChange(PropertyChangeEvent evt)
	{
	}

	/**
	 * @param subclass decides what to do if layout property event is fired
	 */
	protected void handleLayoutChange(PropertyChangeEvent evt)
	{
	}

	/**
	 * handles change in bounds, to be overridden by subclass
	 */
	protected void handleBoundsChange(PropertyChangeEvent evt)
	{
	}
	
	/**
	 * Handles change in name - to be overridden by subclasses
	 */
	protected void handleTextChange(PropertyChangeEvent evt)
	{
	}
	
	/**
	 * handles change in completeness of a stream descriptor, to be overridden by subclass
	 */
	protected void handleCompletenessChange(PropertyChangeEvent evt)
	{
	}
}
